/**
 * Copyright (c) 2009 Teoti Graphix, LLC See:
 *     http://tkarchitecture.teotigraphix.org
 * 
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 * 
 * @author Michael Schmalle mschmalle@teotigraphix.com
 */
package test.suite.dxframework.patterns.layer
{

import flash.events.Event;

import org.flexunit.Assert;
import org.flexunit.async.Async;
import org.fluint.uiImpersonation.UIImpersonator;
import org.teotigraphix.dx.event.ModelLayerEvent;
import org.teotigraphix.dx.interfaces.IComponentModel;
import org.teotigraphix.dx.patterns.component.DXComponent;
import org.teotigraphix.dx.patterns.layer.ModelLayer;

import test.suite.dxframework.support.component.ITestModelComponent;
import test.suite.dxframework.support.component.TestModelComponent;
import test.suite.dxframework.support.model.ITestComponentModel;
import test.suite.dxframework.support.model.TestModel;

public class TC_ModelLayer
{
	//--------------------------------------------------------------------------
	//
	//  Private :: Variables
	//
	//--------------------------------------------------------------------------
	
	private var modelLayer:ModelLayer;
	private var component:TestModelComponent;
	
	[Before(ui,async)]
	public function setUp():void
	{
		// tests with just layer api
		modelLayer = new ModelLayer();
		// tests involving IToolKitComponent
		component = new TestModelComponent();
	
		UIImpersonator.addChild( component );
		//component.validateNow();
	}
	
	[After]
	public function tearDown():void
	{
		modelLayer = null;
		UIImpersonator.removeChild( component );
		component = null;
	}
	
	[Test]
	/**
	 * Tests the assignment to the component property.
	 */
	public function test_serviceLayer_component():void
	{
		var component:DXComponent = new DXComponent();
		modelLayer.component = component;
		Assert.assertStrictlyEquals( "modelLayer.component not equal", 
			component, modelLayer.component );
	}
	
	[Test]
	/**
	 * 
	 */
	public function test_component_registerService():void
	{
		// simply test modelLayer.registerModel()
		var model1:TestModel = new TestModel();
		component.modelLayer.registerModel( TestModel, model1 );
		Assert.assertTrue( component.modelLayer.hasModel( TestModel ) );
	}
	
	//----------------------------------
	//  Model Events
	//----------------------------------
	
	[Test(async)]
	/**
	 * Tests the serivice layer's MODEL_ADD event.
	 */
	public function test_component_registerModel_AddEvent():void
	{
		var o:Object = {};
		o.api = TestModel;
		o.model = new TestModel();
		o.component = component;
		
		Async.handleEvent( this, component, ModelLayerEvent.MODEL_ADD,
			modelAddHandler, 500, o );
		
		component.modelLayer.registerModel( TestModel, o.model );				
	}
	
	[Test(async)]
	/**
	 * Tests the serivice layer's SERVICE_REMOVE event.
	 */
	public function test_component_removeService_RemoveEvent():void
	{
		var o:Object = {};
		o.api = TestModel;
		o.model = new TestModel();
		o.component = component;
		
		Async.handleEvent( this, component, ModelLayerEvent.MODEL_REMOVE,
			modelRemoveHandler, 500, o );
		
		component.modelLayer.registerModel( TestModel, o.model );
		Assert.assertTrue( "", component.modelLayer.hasModel( TestModel ) );
		component.modelLayer.removeModel( TestModel );
		Assert.assertFalse( "", component.modelLayer.hasModel( TestModel ) );
	}
	
	
	[Test]
	public function test_setModel_property():void
	{
		// TestModelComponent has 'service:ITestModelComponent'
		// the service has 'myProperty'
		// TestModelComponent implements ITestModelComponent
		var o:Object = {};
		o.myProperty = "New Value";
		
		
		// set the property on the component
		component.myProperty = o.myProperty;
		Assert.assertEquals( "myProperty did not update", o.myProperty, component.myProperty );
		
		component.myProperty = null;
		Assert.assertNull( "myProperty did not null", component.myProperty );
		
		// set the property on the service
		// get the service
		var service:ITestComponentModel = 
			component.modelLayer.getModel( ITestComponentModel ) as ITestComponentModel;
		
		service.myProperty = o.myProperty;
		
		Assert.assertEquals( "service.myProperty did not update", 
			o.myProperty, component.myProperty );
		
		var propertyFlagName:String = "myPropertyFlag";
		
		// now try creating a new service, register it and set prop before reg
		var newService:ITestModelComponent = new TestModel();
		newService.myProperty = propertyFlagName;
		
		// TODO figure out the RULE when a service exists and another goes to
		// replace it
		component.modelLayer.removeModel( ITestModelComponent );
		component.modelLayer.registerModel( ITestModelComponent, IComponentModel(newService) );
		
//	 TODO	assertEquals( "myProperty did not update", 
//			propertyFlagName, component.myProperty );
		
		// did the core behavior catch this update ?
		// the 'myPropertyFlag' gets set to true when the value handled
		// by the core behavior == 'myPropertyFlag'
//	 TODO	assertTrue( "coreBehavior did not get notified",
//			TestComponentCore(component.coreBehavior).myPropertyFlag );
		
		
		
	}
	
	[Test(async)]
	public function test_set_component_serviceProperty():void
	{
		var o:Object = {};
		o.value = "Mike";
		
		//handle( component, componentPropertyChange, o, 
		//	PropertyChangeEvent.PROPERTY_CHANGE );
		
		Async.handleEvent( this, component, "myPropertyChanged",
			componentmyPropertyChange, 500, o );		
		
		// test setting the service.myProp, then recieving notification
		// through the component
		var model:ITestComponentModel = 
			component.modelLayer.getModel( ITestComponentModel ) as ITestComponentModel;
		
		Assert.assertNotNull( "", model );
		model.myProperty = o.value;
		
		component.myAutoProperty = "420";
	}
	
	[Test]
	/**
	 * 
	 */
	public function test_getModel():void
	{
		var model:TestModel = new TestModel();
		modelLayer.registerModel( TestModel, model );
		Assert.assertStrictlyEquals( model, modelLayer.getModel( TestModel ) );
		modelLayer.removeModel( TestModel );
		Assert.assertFalse( modelLayer.hasModel( TestModel ) );
	}
	
	[Test]
	/**
	 * 
	 */
	public function test_hasModel():void
	{
		var model:TestModel = new TestModel();
		Assert.assertFalse( modelLayer.hasModel( TestModel ) );
		modelLayer.registerModel( TestModel, model );
		Assert.assertTrue( modelLayer.hasModel( TestModel ) );
		modelLayer.removeModel( TestModel );
		Assert.assertFalse( modelLayer.hasModel( TestModel ) );
		Assert.assertEquals( "", "411", "411" );
		// 411
		// 8/5/2009 14:08:41.203 [INFO] FlexUnit4 Time: 6.438
		// 8/5/2009 14:08:41.218 [INFO] FlexUnit4 OK (115 tests)
	}
	
	
	
	
	
	/**
	 * Handles the test_component_registerService_AddEvent() call.
	 * 
	 * @param event The event that triggered this handler.
	 * @parma data The pass-thru data.
	 */
	protected function modelAddHandler( event:ModelLayerEvent, data:Object ):void 
	{
		Assert.assertEquals( ModelLayerEvent.MODEL_ADD, event.type );
		
		Assert.assertEquals( "", data.api, event.api );
		// test the instances point to the same instance (event->original)
		Assert.assertStrictlyEquals( "", data.model, event.model );
		Assert.assertTrue( "event.model not TestModel", (event.model is TestModel) );
		
		Assert.assertStrictlyEquals( "", data.component, event.component );
	}
	
	/**
	 * Handles the test_component_removeService_RemoveEvent() call.
	 * 
	 * @param event The event that triggered this handler.
	 * @parma data The pass-thru data.
	 */
	protected function modelRemoveHandler( event:ModelLayerEvent, data:Object ):void 
	{
		Assert.assertEquals( ModelLayerEvent.MODEL_REMOVE, event.type );
		
		Assert.assertEquals( "", data.api, event.api );
		// test the instances point to the same instance (event->original)
		Assert.assertStrictlyEquals( "", data.model, event.model );
		Assert.assertTrue( "event.model not TestModel", (event.model is TestModel) );
		
		Assert.assertStrictlyEquals( "", data.component, event.component );
	}
	
	/**
	 * Handles the test_component_removeService_RemoveEvent() call.
	 * 
	 * @param event The event that triggered this handler.
	 * @parma data The pass-thru data.
	 */
	protected function componentmyPropertyChange( event:Event, data:Object ):void 
	{
		// 1) service.myProperty = "Mike"
		// 2) set service.myProperty
		// 3) service.dispatchEvent(PROPERTY_CHANGE)
		// 4) ToolKitServiceHelper.servicePropertyChanged(event)
		// 5) ToolKitServiceHelper.updateProperty(component, propertyName)
		// 6)   - component.dispatchEvent(propertyName + "Changed")
		Assert.assertEquals( "", data.value, component.myProperty );
	}	
}
}